///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_ZZ_OPERATORS_H_
#define _BUOLA_ZZ_OPERATORS_H_

#include <buola/zz/zstarop.h>
#include <buola/zz/zoptionalop.h>
#include <buola/zz/zplusop.h>
#include <buola/zz/zlistop.h>
#include <buola/zz/znotop.h>
#include <buola/zz/zandop.h>
#include <buola/zz/zomitop.h>
#include <buola/zz/zdifferenceop.h>
#include <buola/zz/zalternativeop.h>
#include <buola/zz/zsequenceop.h>
#include <buola/zz/zaction.h>
#include <buola/zz/zcapture.h>
#include <type_traits>

#include <buola/zz/detail/enablers.h>

namespace buola { namespace zz {

template<typename tA>
CActionCreator<const tA&> operator++(const ZBase<tA> &pA,int)
{
    return {pA.Derived()};
}

template<typename tA>
CActionCreator<tA&&> operator++(ZBase<tA> &&pA,int)
{
    return {std::move(pA.Derived())};
}

template<typename tA>
CAttributeCapture<const tA&> operator--(const ZBase<tA> &pA,int)
{
    return {pA.Derived()};
}

template<typename tA>
CAttributeCapture<tA&&> operator--(ZBase<tA> &&pA,int)
{
    return {std::move(pA.Derived())};
}

template<typename tA>
ZStarOp<tA> operator*(const ZBase<tA> &pA)
{
    return ZStarOp<tA>(pA.Derived());
}

template<typename tA>
ZStarOp<tA> operator*(ZBase<tA> &&pA)
{
    return ZStarOp<tA>(std::move(pA.Derived()));
}

template<typename tA>
ZOptionalOp<tA> operator-(const ZBase<tA> &pA)
{
    return ZOptionalOp<tA>(pA.Derived());
}

template<typename tA>
ZOptionalOp<tA> operator-(ZBase<tA> &&pA)
{
    return ZOptionalOp<tA>(std::move(pA.Derived()));
}

template<typename tA>
ZPlusOp<tA> operator+(const ZBase<tA> &pA)
{
    return ZPlusOp<tA>(pA.Derived());
}

template<typename tA>
ZPlusOp<tA> operator+(ZBase<tA> &&pA)
{
    return ZPlusOp<tA>(std::move(pA.Derived()));
}

template<typename tA>
ZNotOp<tA> operator!(const ZBase<tA> &pA)
{
    return ZNotOp<tA>(pA.Derived());
}

template<typename tA>
ZNotOp<tA> operator!(ZBase<tA> &&pA)
{
    return ZNotOp<tA>(std::move(pA.Derived()));
}

template<typename tA>
ZAndOp<tA> operator&(const ZBase<tA> &pA)
{
    return ZAndOp<tA>(pA.Derived());
}

template<typename tA>
ZAndOp<tA> operator&(ZBase<tA> &&pA)
{
    return ZAndOp<tA>(std::move(pA.Derived()));
}

template<typename tA>
ZOmitOp<tA> operator~(const ZBase<tA> &pA)
{
    return ZOmitOp<tA>(pA.Derived());
}

template<typename tA>
ZOmitOp<tA> operator~(ZBase<tA> &&pA)
{
    return ZOmitOp<tA>(std::move(pA.Derived()));
}

template<typename tLH,typename tRH>
ZListOp<tLH,tRH> operator%(const ZBase<tLH> &pLH,const ZBase<tRH> &pRH)
{
    return {pLH.Derived(),pRH.Derived()};
}

template<typename tLH,typename tRH>
ZListOp<tLH,tRH> operator%(ZBase<tLH> &&pLH,const ZBase<tRH> &pRH)
{
    return {std::move(pLH.Derived()),pRH.Derived()};
}

template<typename tLH,typename tRH>
ZListOp<tLH,tRH> operator%(const ZBase<tLH> &pLH,ZBase<tRH> &&pRH)
{
    return {pLH.Derived(),std::move(pRH.Derived())};
}

template<typename tLH,typename tRH>
ZListOp<tLH,tRH> operator%(ZBase<tLH> &&pLH,ZBase<tRH> &&pRH)
{
    return {std::move(pLH.Derived()),std::move(pRH.Derived())};
}

template<typename tLH,typename tRH>
ZDifferenceOp<tLH,tRH> operator-(const ZBase<tLH> &pLH,const ZBase<tRH> &pRH)
{
    return {pLH.Derived(),pRH.Derived()};
}

template<typename tLH,typename tRH>
ZDifferenceOp<tLH,tRH> operator-(ZBase<tLH> &&pLH,const ZBase<tRH> &pRH)
{
    return {std::move(pLH.Derived()),pRH.Derived()};
}

template<typename tLH,typename tRH>
ZDifferenceOp<tLH,tRH> operator-(const ZBase<tLH> &pLH,ZBase<tRH> &&pRH)
{
    return {pLH.Derived(),std::move(pRH.Derived())};
}

template<typename tLH,typename tRH>
ZDifferenceOp<tLH,tRH> operator-(ZBase<tLH> &&pLH,ZBase<tRH> &&pRH)
{
    return {std::move(pLH.Derived()),std::move(pRH.Derived())};
}

template<typename tLH,typename tRH>
typename detail::MNaryConcat<tLH,tRH,ZSequenceOp>::type
operator>>(const ZBase<tLH> &pLH,const ZBase<tRH> &pRH)
{
    return {typename detail::MNaryConcat<tLH,tRH,ZSequenceOp>::tCombine(),pLH.Derived(),pRH.Derived()};
}

template<typename tLH,typename tRH>
typename detail::MNaryConcat<tLH,tRH,ZSequenceOp>::type
operator>>(ZBase<tLH> &&pLH,const ZBase<tRH> &pRH)
{
    return {typename detail::MNaryConcat<tLH,tRH,ZSequenceOp>::tCombine(),std::move(pLH.Derived()),pRH.Derived()};
}

template<typename tLH,typename tRH>
typename detail::MNaryConcat<tLH,tRH,ZSequenceOp>::type
operator>>(const ZBase<tLH> &pLH,ZBase<tRH> &&pRH)
{
    return {typename detail::MNaryConcat<tLH,tRH,ZSequenceOp>::tCombine(),pLH.Derived(),std::move(pRH.Derived())};
}

template<typename tLH,typename tRH>
typename detail::MNaryConcat<tLH,tRH,ZSequenceOp>::type
operator>>(ZBase<tLH> &&pLH,ZBase<tRH> &&pRH)
{
    return {typename detail::MNaryConcat<tLH,tRH,ZSequenceOp>::tCombine(),std::move(pLH.Derived()),std::move(pRH.Derived())};
}

template<typename tLH,typename tRH>
typename detail::MNaryConcat<tLH,tRH,ZAlternativeOp>::type
operator|(const ZBase<tLH> &pLH,const ZBase<tRH> &pRH)
{
    return {typename detail::MNaryConcat<tLH,tRH,ZAlternativeOp>::tCombine(),pLH.Derived(),pRH.Derived()};
}

template<typename tLH,typename tRH>
typename detail::MNaryConcat<tLH,tRH,ZAlternativeOp>::type
operator|(ZBase<tLH> &&pLH,const ZBase<tRH> &pRH)
{
    return {typename detail::MNaryConcat<tLH,tRH,ZAlternativeOp>::tCombine(),std::move(pLH.Derived()),pRH.Derived()};
}

template<typename tLH,typename tRH>
typename detail::MNaryConcat<tLH,tRH,ZAlternativeOp>::type
operator|(const ZBase<tLH> &pLH,ZBase<tRH> &&pRH)
{
    return {typename detail::MNaryConcat<tLH,tRH,ZAlternativeOp>::tCombine(),pLH.Derived(),std::move(pRH.Derived())};
}

template<typename tLH,typename tRH>
typename detail::MNaryConcat<tLH,tRH,ZAlternativeOp>::type
operator|(ZBase<tLH> &&pLH,ZBase<tRH> &&pRH)
{
    return {typename detail::MNaryConcat<tLH,tRH,ZAlternativeOp>::tCombine(),std::move(pLH.Derived()),std::move(pRH.Derived())};
}

/*namespace zz*/ } /*namespace buola*/ }

#endif
